#include <ALE.h>
#include <TransformComponent.h>
#include <MoveComponent.h>
#include <RenderComponent.h>

#if defined(_DEBUG)
	#pragma comment(lib, "ALEd.lib")
	#pragma comment(lib, "dxerr.lib")
	#pragma comment(lib, "luaplusstatic51d.lib")
#else
	#pragma comment(lib, "ALE.lib")
	#pragma comment(lib, "luaplusstatic51.lib")
#endif

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "fmodex_vc.lib")

class TestView : public HumanView
{
public:
	TestView();

	virtual void VAttach(GameViewId id, ActorId aid = 0) override;
protected:
	void BuildInitialScene();
	std::shared_ptr<Scene2D> m_pScene;
	std::shared_ptr<Camera2D> m_pCamera;
};

TestView::TestView() : HumanView()
{
	m_pScene.reset(ALE_NEW Scene2D());
	Area area(Vec2(0,0), Vec2(g_pApp->GetScreenWidth(), g_pApp->GetScreenHeight()));
	m_pCamera.reset(ALE_NEW Camera2D(area));
	m_pScene->SetCamera(m_pCamera);
	m_pScene->AddChild(m_pCamera);
}

void TestView::VAttach(GameViewId id, ActorId aid)
{
	HumanView::VAttach(id, aid);
	BuildInitialScene();
}

void TestView::BuildInitialScene()
{
	VPushElement(m_pScene);
	VRestore();
}

class TestProc : public Process
{
public:
	TestProc() : Process() { }
	void VUpdate(double deltaDecs) override;
	void VOnSuccess() override;
};

class TestGame : public BaseGame
{
	ActorFactory* m_pFactory;
public:
	TestGame() : BaseGame()
	{
		m_pFactory = NULL;
	}
	virtual ~TestGame();

	bool VPreload() override { return BaseGame::VPreload();}
	bool VInit() override;
	void VUpdate(double deltaSecs) override;

	void OnTestEvent(IEventPtr pEvent);
	void OnMoveActor(IEventPtr pEvent);
};

bool TestGame::VInit()
{
	EventListenerDelegate listener = fastdelegate::MakeDelegate(this, &TestGame::OnTestEvent);
	IEventManager::Get()->VAddListener(listener, Event_Test::sk_eventType);
	EventListenerDelegate listener2 = fastdelegate::MakeDelegate(this, &TestGame::OnMoveActor);
	IEventManager::Get()->VAddListener(listener2, Event_Move_Actor_2D::sk_eventType);

	StrongProcessPtr proc(ALE_NEW TestProc());
	m_pProcessManager->AttachProcess(proc);


	std::shared_ptr<IGameView> pView;
	pView.reset(ALE_NEW TestView());
	VAddView(pView);

	m_pFactory = ALE_NEW ActorFactory();
	StrongActorPtr pActor = m_pFactory->CreateActor("Strings/TestActor.xml");
	VAddActor(pActor);

	return BaseGame::VInit();
}

void TestGame::VUpdate(double deltaSecs)
{
	BaseGame::VUpdate(deltaSecs);
}

TestGame::~TestGame()
{
	SAFE_DELETE(m_pFactory);
}

void TestGame::OnTestEvent(IEventPtr pEvent)
{
	double counter = 0;

	StrongActorPtr pActor = VGetActor(1);
	if(pActor)
	{
		std::weak_ptr<TransformComponent2D> pComponent = pActor->GetComponent<TransformComponent2D>(TransformComponent2D::g_ID);
		if(std::shared_ptr<TransformComponent2D> pCom = pComponent.lock())
			counter = pCom->GetPosition().x;
	}

	TCHAR wbuffer[50];
	swprintf(wbuffer, L"Test Event %.4f", counter);
	MessageBox(g_pApp->GetHWND(), wbuffer, L"Event", MB_OK);
}

void TestGame::OnMoveActor(IEventPtr pEvent)
{
	std::shared_ptr<Event_Move_Actor_2D> castEvent = std::static_pointer_cast<Event_Move_Actor_2D>(pEvent);
	StrongActorPtr pActor = VGetActor(castEvent->m_id);
	if(pActor)
	{
		std::weak_ptr<TransformComponent2D> pWeakTrans = pActor->GetComponent<TransformComponent2D>(TransformComponent2D::g_ID);
		if (std::shared_ptr<TransformComponent2D> pCom = pWeakTrans.lock())
		{
			pCom->SetPosition(castEvent->m_position);
			pCom->SetOrientation(castEvent->m_orientation);
			pCom->SetSize(castEvent->m_size);
		}
	}
}

class TestApp : public Application
{
public:
	TestApp() : Application()
	{
	}

	TCHAR *VGetGameTitle() { return L"TestApp"; }
	BaseGame* VCreateGame() override;

protected:
};


void TestProc::VUpdate(double deltaSecs)
{
	static double time = 0;

	time += deltaSecs;
	if (time >= 3.0)
		Succeed();
}

void TestProc::VOnSuccess()
{
	IEventPtr pEvent(ALE_NEW Event_Test());
	IEventManager::Get()->VQueueEvent(pEvent);
}

BaseGame* TestApp::VCreateGame()
{
	BaseGame* pGame = ALE_NEW TestGame();
	return pGame;
}

TestApp g_App;

INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	return ALEMain(hInstance, hPrevInstance, GetCommandLineW(), nCmdShow);
	return 0;
}